package com.ansion.basedb.dao.helper;

import com.ansion.log.S;
import com.ansion.pattern.PatternUtils;
import com.ansion.utils.GsonUtil;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;


/**
 * created by zhaoyuntao
 * on 15/03/2022
 * description:
 */
public class TableBean {
    public String tableName;
    public List<ColumnNameBean> columns;
    public List<ItemBean> itemBeans;
    public String error;
    public String result;
    public static final String NULL = "<NULL>";

    public String getColumnInfoString(boolean wrap) {
        StringBuilder columnsString = new StringBuilder();
        if (columns != null) {
            for (ColumnNameBean columnNameBean : columns) {
                columnsString
                        .append("[")
                        .append(columnNameBean.name).append(", ")
                        .append(columnNameBean.typeString)
                        .append(", PK:").append(columnNameBean.isPrimaryKey)
                        .append(", notNull:").append(columnNameBean.notNull)
//                        .append(", unique:").append(columnNameBean.unique)
                        .append("]").append(wrap ? "\n" : "");
            }
        }
        return columnsString.toString();
    }

    public List<String> getRowInfoString(boolean formatJson, boolean formatBlob, int rowMaxLength) {
        List<String> rowInfoStrings = new ArrayList<>();
        if (itemBeans != null && columns != null) {
            int i = 0;
            for (ItemBean itemBean : itemBeans) {
                StringBuilder valueString = new StringBuilder();
                valueString.append("(")
                        .append(i++)
                        .append("):  ");
                if (itemBean.columnBeanMap == null) {
                    valueString.append("itemBean.columnBeanMap == null");
                } else {
                    for (Map.Entry<String, ColumnBean> entry : itemBean.columnBeanMap.entrySet()) {
                        String name = entry.getKey();
                        ColumnBean columnBean = entry.getValue();

                        if (columnBean != null) {
                            String value = String.valueOf(columnBean.value);
                            boolean isJson = false;
                            if (formatBlob && "blobData".equalsIgnoreCase(columnBean.name)) {
                                try {
                                    value = formatJson(new String(GsonUtil.fromJson(value, byte[].class)), rowMaxLength);
                                    isJson = true;
                                } catch (Exception e) {
                                    S.e(e);
                                }
                            } else if (formatJson && PatternUtils.matched("\\{.*\\}", value)) {
                                try {
                                    value = "\n" + new JSONObject(value).toString(2) + "\n";
                                    isJson = true;
                                } catch (JSONException ignore) {
                                }
                            } else if (rowMaxLength > 0 && value.length() > rowMaxLength) {
                                value = cutString(value, rowMaxLength);
                            }
                            valueString.append(isJson ? "\n[" : "[").append(name).append(": ").append(value).append("] ");
                        } else {
//                            valueString.append("[").append(name).append(": No such Column] ");
                        }
//                        }
                    }
                }
                rowInfoStrings.add(valueString.toString());
            }
        } else {
            rowInfoStrings.add("Result or column is empty!");
        }
        return rowInfoStrings;
    }

    private String formatJson(String value, int rowMaxLength) {
        try {
            JSONObject jsonObject = new JSONObject(value);
            hideObject(jsonObject, rowMaxLength);
            value = jsonObject.toString(2);
        } catch (JSONException ignore) {
            try {
                JSONArray jsonArray = new JSONArray(value);
                hideArray(jsonArray, rowMaxLength);
                value = jsonArray.toString();
            } catch (JSONException ignore2) {
            }
        }
        return value;
    }

    private void hideObject(JSONObject jsonObject, int rowMaxLength) {
        Iterator<String> a = jsonObject.keys();
        while (a.hasNext()) {
            String key = a.next();
            Object object = jsonObject.opt(key);
//            S.s("key:" + key + " " + object);
            hideObject(jsonObject, object, key, rowMaxLength);
        }
    }

    private void hideArray(JSONArray valueArray, int rowMaxLength) {
        for (int i = 0; i < valueArray.length(); i++) {
            hideArray(valueArray, valueArray.opt(i), i, rowMaxLength);
        }
    }

    private void hideObject(JSONObject jsonObject, Object object, String key, int rowMaxLength) {
        if (object instanceof String) {
            String stringValue = (String) object;
//            S.s("key:" + key + " " + stringValue);
            if (rowMaxLength > 0 && stringValue.length() > rowMaxLength) {
                try {
                    jsonObject.put(key, cutString(stringValue, rowMaxLength));
                } catch (JSONException ignore) {
                }
            }
        } else if (object instanceof JSONObject) {
            JSONObject valueObject = (JSONObject) object;
            hideObject(valueObject, rowMaxLength);
        } else if (object instanceof JSONArray) {
            JSONArray valueArray = (JSONArray) object;
            hideArray(valueArray, rowMaxLength);
        }
    }

    private void hideArray(JSONArray jsonArray, Object object, int position, int rowMaxLength) {
        if (object instanceof String) {
            String stringValue = (String) object;
            if (rowMaxLength > 0 && stringValue.length() > rowMaxLength) {
                try {
                    jsonArray.remove(position);
                    jsonArray.put(position, cutString(stringValue, rowMaxLength));
                } catch (JSONException ignore) {
                }
            }
        } else if (object instanceof JSONObject) {
            JSONObject valueObject = (JSONObject) object;
            hideObject(valueObject, rowMaxLength);
        } else if (object instanceof JSONArray) {
            JSONArray valueArray = (JSONArray) object;
            hideArray(valueArray, rowMaxLength);
        }
    }

    private String cutString(String string, int rowMaxLength) {
        int half = rowMaxLength / 2;
        int rest = rowMaxLength - half;
        return (string == null || string.length() <= rowMaxLength) ? string : string.substring(0, half) + "..<" + (string.length() - rowMaxLength) + ">.." + string.substring(string.length() - rest);
    }
}
